#%% Change working directory from the workspace root to the ipynb file location. Turn this addition off with the DataScience.changeDirOnImportExport setting
# ms-python.python added
import os
try:
	os.chdir(os.path.join(os.getcwd(), 'scikit-learn机器学习常用算法原理和编程实战\\Data-Mining\notebook'))
	print(os.getcwd())
except:
	pass
#%% [markdown]
# **内容:**
# - 逻辑回归算法原理
# - 用梯度下降算法求解逻辑回归算法的模型参数
# - 正则化及正则化应用
# - L1范数和L2范数的含义及其作为模型正则项的区别
# - 用逻辑回归算法求解乳腺癌检测问题
#%% [markdown]
# # 1.算法原理
# 
# 1.预测函数:  
# 需要找出一个预测函数模型,使其值输出在[0,1]之间,然后选择一个基准值,如0.5,如果算出来的预测值大于0.5,就认为预测值是1,反之认为其是0,选择:
# $$
# g(x)=\frac{1}{1+e^{-z}}
# $$
# 来作为其预测函数,其中e是自然对数的底数.函数g(z)称为Sigmoid函数,也称为Logistic函数.以z为横坐标,以g(z)为纵坐标,画出图形如下:

#%%
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
get_ipython().run_line_magic('matplotlib', 'inline')


#%%
sns.set_style('whitegrid')


#%%
x=np.linspace(-6,6,200)
y=1/(1+np.exp(-x))

plt.plot(x,y)
plt.show()

#%% [markdown]
# 可以看到,当z=0时,g(z)=0.5,当z>0时,g(z)>0.5,当z越来越大时,g(z)无限接近于1.当z越来越小的时候,起无限接近于0.这正是我们想要的针对二元分类算法的预测函数.  
# 结合线性回归函数的预测函数,$ h_0(x)=\theta^Tx $,假设另$ z(x)=\theta^Tx $,则逻辑回归算法的预测函数如下:
# $$
# h_0(x)=g(z)=g(\theta^Tx)=\frac{1}{1+e^{-\theta^Tx}}
# $$
# 
# $ h_0(x)$表示在输入值为x,参数为$ \theta $的条件下Y=1的概率.用概率论的公式可以写成:
# $$
#  h_0(x)=P(y=1|x,\theta)
# $$
# > 在输入x及参数$ \theta$的条件下,y=1的概率.这是一个条件概率公式.对于二元分类法来说,这是个非黑即白的世界.
#%% [markdown]
# 2. 判定边界  
# 逻辑回归算法的预测函数由下面两个公式给出:
# $$
# h_0(x)=g(\theta^Tx)
# $$
# $$
# g(x)=\frac{1}{1+e^{-z}}
# $$
# 假定y=1的判定条件是$h_0(x)\geqslant0.5$,y=0的判定条件是$h_0(x)\leqslant0.5$,则可以推导出y=1的判定条件就是$\theta^Tx\geqslant 0$,y=0的判定条件就是$\theta^Tx<0$.所以$\theta^Tx=0$就是我们的判定边界.
#%% [markdown]
# 3. 成本函数  
# 线性模型的成本函数去推导逻辑回归的成本函数是不合适的,因为这样出来的函数太复杂.为了容易找到成本函数的最小值.我们分成y=1和y=0两种情况来分辨考虑其预测值和真实值的误差.
# 
#%% [markdown]
# 成本函数:
# $$
# J(\theta)=-\frac{1}{m}\left[\sum_{i=1}^my^{(i)}\log(h_0(x^{i}))+(1-y^{i})log(1-h_0(x^(i))\right]
# $$
#%% [markdown]
# **4.梯度下降算法**  
# 和线性回归类似,我们也可以使用梯度下降算法来求解逻辑回归模型参数.根据梯度下降算法的定义.可以得到:
# $$
# \theta_j=\theta_j-\alpha\frac{\delta}{\delta\theta_j}J(\theta)
# $$
# 这里的关键是求解成本函数的偏导数,最终推倒出来的梯度下降算法的公式为:
# $$
# \theta_j=\theta_j-\alpha\frac{1}{m}\sum_{i=1}{m}(h_0(x^{i}-y^{(i)})x_j^{(i)}
# $$
#%% [markdown]
# ## 2.多元分类
# 
# 逻辑回归模型除了可以解决二元分类问题,还可以解决多元分类的问题.针对多元分类问题:y={0,1,2...n},总共有n+1个类别.其解决的基本思路是,首先把问题转换为二元分类问题.即y=0是一个类别,y={1,2,3...n}是一个类别.然后分别计算两个类别的概率.接着把y=1作为一个类别,剩余的做另外一个类别,以此推广.总共需要n+1个预测函数.预测出来的概率最高的那个类别,就是样本所属的类别.
#%% [markdown]
# ## 3.正则化
# 正则化也是用来解决模型过拟合的一个办法:
# * 保留所有的特征,减小特征的权重$ \theta_j $的值,确保所有特征对预测值都有少量的贡献.
# * 当每个特征$x_i$对预测值y都有少量贡献时,这样的模型可以良好的工作,这就是正则化的目的,可以用它来解决特征过多时,过拟合的问题.
#%% [markdown]
# ### 3.1 线性回归模型正则化
# 线性回归模型的成本函数正则化:
# $$
# J(\theta)=\frac{1}{2m} \left[\sum_{i=1}^m(h_0(x^{i}-y^{i})^2 \right]+\lambda\sum_{i=1}^n\theta_j^2
# $$
# - 公式的前半部分是线性回归模型的成本函数,也称为预测值和实际值的误差.
# - 后半部分为加入的正则项.
#     - $\lambda$的值有两个目的:纪要维持对训练样本的拟合,又要避免对训练样本的过拟合.如果$\lambda$的值太大,则能确保不出现过拟合,但可能也会导致出现对训练样本的欠拟合.
#     
# 从数学的角度看,成本函数增加了一个正则项后,成本函数不再唯一的由预测值和真实值的误差决定,还和参数$\theta$的大小有关.有了这个限制后,要实现成本函数的最小目的,其就不能随意取值了.比如$\theta$值较大的时候,会导致预测值和真实值的误差值很小,但会导致$\theta_j^2$很大.最终结果还是会导致成本函数太大.这样通过条件参数$\lambda$,就可以控制正则项的权重.从而避免线性回归函数的过拟合.
# 
# ### 3.2 逻辑回归模型正则化
# 
#%% [markdown]
# ## 4.算法参数
# 
# 1. 正则项权重
# 2. L1/L2范数

#%%
from sklearn.datasets import load_breast_cancer
cancer=load_breast_cancer()

#%%
X=cancer.data
y=cancer.target

print("data shape: {0};no.positive:{1};no.megative:{2}".format(X.shape,y[y==1].shape[0],y[y==0].shape[0]))
print(cancer.data[0])

#%%
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2)

#%%
from sklearn.linear_model import LogisticRegression

model=LogisticRegression()
model.fit(X_train,y_train)

train_score=model.score(X_train,y_train)
test_score=model.score(X_test,y_test)

print("Train Score:",train_score)
print("Test SCore:",test_score)

#%%
import numpy as np
y_pred=model.predict(X_test)
print("matchs:{0}/{1}".format(np.equal(y_pred,y_test).shape[0],y_test.shape[0]))

#%%
